home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Interactive Reference Guide / C-C++ Interactive Reference Guide.iso / c_ref / csource5 / 365_01 / fmt.c < prev    next >
C/C++ Source or Header  |  1992-04-06  |  5KB  |  267 lines

  1. /* fmt.c */
  2.  
  3. /* usage: fmt [-width] [files]...
  4.  *
  5.  * Fmt rearrages text in order to make each line have roughly the
  6.  * same width.  Indentation and word spacing is preserved.
  7.  *
  8.  * The default width is 72 characters, but you can override that via -width.
  9.  * If no files are given on the command line, then it reads stdin.
  10.  */
  11.  
  12. #include <stdio.h>
  13.  
  14. #ifndef TRUE
  15. # define TRUE    1
  16. # define FALSE    0
  17. #endif
  18.  
  19.  
  20.  
  21. int    width = 72;    /* the desired line width */
  22. int    isblank;    /* is the current output line blank? */
  23. int    indent;        /* width of the indentation */
  24. char    ind[512];    /* indentation text */
  25. char    word[1024];    /* word buffer */
  26.  
  27. /* This function displays a usage message and quits */
  28. void usage()
  29. {
  30.     fprintf(stderr, "usage: fmt [-width] [files]...\n");
  31.     exit(2);
  32. }
  33.  
  34.  
  35.  
  36. /* This function outputs a single word.  It takes care of spacing and the
  37.  * newlines within a paragraph.
  38.  */
  39. void putword()
  40. {
  41.     int        i;        /* index into word[], or whatever */
  42.     int        ww;        /* width of the word */
  43.     int        sw;        /* width of spacing after word */
  44.     static int    psw;        /* space width of previous word */
  45.     static int    tab;        /* the width of text already written */
  46.  
  47.  
  48.     /* separate the word and its spacing */
  49.     for (ww = 0; word[ww] && word[ww] != ' '; ww++)
  50.     {
  51.     }
  52.     sw = strlen(word) - ww;
  53.     word[ww] = '\0';
  54.  
  55.     /* if no spacing (that is, the word was at the end of the line) then
  56.      * assume 1 space unless the last char of the word was punctuation
  57.      */
  58.     if (sw == 0)
  59.     {
  60.         sw = 1;
  61.         if (word[ww - 1] == '.' || word[ww - 1] == '?' || word[ww - 1] == '!')
  62.             sw = 2;
  63.     }
  64.  
  65.     /* if this is the first word on the line... */
  66.     if (isblank)
  67.     {
  68.         /* output the indentation first */
  69.         fputs(ind, stdout);
  70.         tab = indent;
  71.     }
  72.     else /* text has already been written to this output line */
  73.     {
  74.         /* will the word fit on this line? */
  75.         if (psw + ww + tab <= width)
  76.         {
  77.             /* yes - so write the previous word's spacing */
  78.             for (i = 0; i < psw; i++)
  79.             {
  80.                 putchar(' ');
  81.             }
  82.             tab += psw;
  83.         }
  84.         else
  85.         {
  86.             /* no, so write a newline and the indentation */
  87.             putchar('\n');
  88.             fputs(ind, stdout);
  89.             tab = indent;
  90.         }
  91.     }
  92.  
  93.     /* write the word itself */
  94.     fputs(word, stdout);
  95.     tab += ww;
  96.  
  97.     /* remember this word's spacing */
  98.     psw = sw;
  99.  
  100.     /* this output line isn't blank anymore. */
  101.     isblank = FALSE;
  102. }
  103.  
  104.  
  105.  
  106. /* This function reformats text. */
  107. void fmt(in)
  108.     FILE    *in;        /* the name of the input stream */
  109. {
  110.     int    ch;        /* character from input stream */
  111.     int    prevch;        /* the previous character in the loop */
  112.     int    i;        /* index into ind[] or word[] */
  113.     int    inword;        /* boolean: are we between indent & newline? */
  114.  
  115.  
  116.     /* for each character in the stream... */
  117.     for (indent = -1, isblank = TRUE, inword = FALSE, i = 0, prevch = '\n';
  118.          (ch = getc(in)) != EOF;
  119.          prevch = ch)
  120.     {
  121.         /* is this the end of a line? */
  122.         if (ch == '\n')
  123.         {
  124.             /* if end of last word in the input line */
  125.             if (inword)
  126.             {
  127.                 /* if it really is a word */
  128.                 if (i > 0)
  129.                 {
  130.                     /* output it */
  131.                     word[i] = '\0';
  132.                     putword();
  133.                 }
  134.             }
  135.             else /* blank line in input */
  136.             {
  137.                 /* finish the previous paragraph */
  138.                 if (!isblank)
  139.                 {
  140.                     putchar('\n');
  141.                     isblank = TRUE;
  142.                 }
  143.  
  144.                 /* output a blank line */
  145.                 putchar('\n');
  146.             }
  147.  
  148.             /* continue with next input line... */
  149.             indent = -1;
  150.             i = 0;
  151.             inword = FALSE;
  152.             continue;
  153.         }
  154.  
  155.         /* if we're expecting indentation now... */
  156.         if (indent < 0)
  157.         {
  158.             /* if this is part of the indentation... */
  159.             if (ch == ' ' || ch == '\t')
  160.             {
  161.                 /* remember it */
  162.                 ind[i++] = ch;
  163.             }
  164.             else /* end of indentation */
  165.             {
  166.                 /* mark the end of the indentation string */
  167.                 ind[i] = '\0';
  168.  
  169.                 /* calculate the width of the indentation */
  170.                 for (i = indent = 0; ind[i]; i++)
  171.                 {
  172.                     if (ind[i] == '\t')
  173.                         indent = (indent | 7) + 1;
  174.                     else
  175.                         indent++;
  176.                 }
  177.  
  178.                 /* reset the word index */
  179.                 i = 0;
  180.  
  181.                 /* reprocess that last character */
  182.                 ungetc(ch, in);
  183.             }
  184.  
  185.             /* continue in the for-loop */
  186.             continue;
  187.         }
  188.  
  189.         /* if we get here, we're either in a word or in the space
  190.          * after a word.
  191.          */
  192.         inword = TRUE;
  193.  
  194.         /* is this the start of a new word? */
  195.         if (ch != ' ' && prevch == ' ')
  196.         {
  197.             /* yes!  output the previous word */
  198.             word[i] = '\0';
  199.             putword();
  200.  
  201.             /* reset `i' to the start of the word[] buffer */
  202.             i = 0;
  203.         }
  204.         word[i++] = ch;
  205.     }
  206.  
  207.     /* if necessary, write a final newline */
  208.     if (!isblank)
  209.     {
  210.         putchar('\n');
  211.         isblank = TRUE;
  212.     }
  213. }
  214.  
  215.  
  216.  
  217.  
  218.  
  219. int main(argc, argv)
  220.     int    argc;
  221.     char    **argv;
  222. {
  223.     FILE    *in;    /* an input stream */
  224.     int    error;    /* if non-zero, then an error occurred */
  225.     int    i;
  226.  
  227.  
  228.     /* handle the -width flag, if given */
  229.     if (argc > 1 && argv[1][0] == '-')
  230.     {
  231.         width = atoi(argv[1] + 1);
  232.         if (width <= 0)
  233.         {
  234.             usage();
  235.         }
  236.         argc--;
  237.         argv++;
  238.     }
  239.  
  240.     /* if no filenames given, then process stdin */
  241.     if (argc == 1)
  242.     {
  243.         fmt(stdin);
  244.     }
  245.     else /* one or more filenames given */
  246.     {
  247.         for (error = 0, i = 1; i < argc; i++)
  248.         {
  249.             in = fopen(argv[i], "r");
  250.             if (!in)
  251.             {
  252.                 perror(argv[i]);
  253.                 error = 3;
  254.             }
  255.             else
  256.             {
  257.                 fmt(in);
  258.                 fclose(in);
  259.             }
  260.         }
  261.     }
  262.  
  263.     /* exit, possibly indicating an error */
  264.     exit(error);
  265.     /*NOTREACHED*/
  266. }
  267.